package edu.cuit.zhuyimeng.gateway.config;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.cuit.zhuyimeng.gateway.property.DynamicGatewayProperties;
import edu.cuit.zhuyimeng.gateway.property.ServerInfoProperties;
import edu.cuit.zhuyimeng.gateway.service.RouteService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
@Slf4j
public class DynamicNacosRouteConfig implements CommandLineRunner {

    private final ServerInfoProperties serverInfoProperties;

    private final DynamicGatewayProperties dynamicGatewayProperties;

    private final RouteService routeService;

    private final ObjectMapper objectMapper;

    private final Executor executor;

    public void listeningNacosConfig() throws NacosException {
        Properties properties = serverInfoProperties.getProperties() ;
        ConfigService configService = NacosFactory.createConfigService(properties);
        String config = configService.getConfig(dynamicGatewayProperties.getDataId(), dynamicGatewayProperties.getGroup(),Long.parseLong(serverInfoProperties.getTimeout()));
        routesUpdate(config);

        // 监听nacos配置文件的变化
        configService.addListener(dynamicGatewayProperties.getDataId(), dynamicGatewayProperties.getGroup(), new Listener() {
            @Override
            public Executor getExecutor() {
                return executor;
            }

            @Override
            public void receiveConfigInfo(String content) {
                routesUpdate(content);
            }
        });
    }

    @Override
    public void run(String... args) throws Exception {
        if (dynamicGatewayProperties.getEnableDynamicRoutes()) {
            listeningNacosConfig();
        }
    }

    /**
     * 根据gateway配置的额数据，更新理由
     *
     * @param content gateway动态路由配置数据
     **/
    public void routesUpdate(String content) {
        try {
            RouteDefinition[] routeDefinitions = objectMapper.readValue(content, RouteDefinition[].class);

            // 获取存在当前项目中所有的路由ID
            ArrayList<List<String>> routes = routeService.getRoutes();
            List<String> collect = routes.stream().flatMap(Collection::stream).toList();
            List<String> noneMatchIdList = collect.stream().filter((e) -> Arrays.stream(routeDefinitions).noneMatch((t) -> Objects.equals(t.getId(), e))).collect(Collectors.toList());
            for (String id : noneMatchIdList) {
                try {
                    //将多余的路由删除
                    routeService.deleteRoute(id);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            for (RouteDefinition routeDefinition : routeDefinitions) {
                try {
                    routeService.updateRoute(routeDefinition);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (JsonProcessingException e) {
            log.error("Nacos配置文件格式有误，不能将配置的路由结构转为 RouteDefinition.{}", e.getMessage());
            e.printStackTrace();
        }
    }
}
